#include "stdafx.h"
#include <initguid.h>
#include <pimstore.h>
#include "ListDataPoom.h"
#include "Settings.h"
#include "Language.h"
#include "Theme.h"
#include "PoomPictureLoader.h"
#include "PoomData.h"
#include "EdbData.h"
#include "SimManager.h"
#include "CommonWM.h"
#include "ListDetails.h"
#include "GraphicFunctions.h"

#ifdef _DEBUG
#include "crtdbg.h"
#endif

ListDataPoom::ListDataPoom(HWND hWnd, const TCHAR* szCategory)
  : CListBase(hWnd)
{
  this->pCurrFldr = NULL;
  this->pItemCol = NULL;

  // Get the contacts folder.
  PoomData::GetApp()->GetDefaultFolder(olFolderContacts, &this->pCurrFldr);

  categoryName[0] = 0;
  isFavoritesCat = false;
  this->bOnlyFavorites = (szCategory != NULL);

  // Get the contacts Items collection.
  PrepareItemColl(szCategory);

  this->Populate();
}

ListDataPoom::~ListDataPoom()
{
  if (this->pItemCol)
  {
    this->pItemCol->Release();
  }

  if (this->pCurrFldr)
  {
    this->pCurrFldr->Release();
  }
}

void ListDataPoom::Clear()
{
  if (this->pItemCol)
  {
    this->pItemCol->Release();
    this->pItemCol = NULL;
  }

  CListBase::Clear();
}

void ListDataPoom::Reload(const TCHAR* szCategory)
{
  Clear();

  this->bOnlyFavorites = (szCategory != NULL);

  // Get the contacts Items collection.
  PrepareItemColl(szCategory);

#ifdef LOG_ENABLED
  Logger::Log(TEXT("ListDataPoom::Reload"));
#endif

  this->Populate();
}

bool ListDataPoom::ReloadItem(CEOID oid)
{
  int index = this->GetItemIdxByOid(oid);
  if (index >= 0 && BaseItem(index)->GetType() == citPoom)
  {
    IContact* pContact = NULL;
    if (FAILED(PoomData::GetApp()->GetItemFromOid(oid, reinterpret_cast<IDispatch**>(&pContact))))
      return false;
    bool res = FillContact((CListItemPoom*)items[index], pContact, !this->bOnlyFavorites || Settings::enableFavoritesSearch, true);
    pContact->Release();
    return res;
  }
  return false;
}

bool ListDataPoom::PrepareItemColl(const TCHAR* szCategory)
{
  HRESULT hr;

  // Get the contacts Items collection.
  hr = this->pCurrFldr->get_Items(&this->pItemCol);

  ClearHeaderText();

  if (szCategory)
  {
    if (SUCCEEDED(hr) && this->bOnlyFavorites)
    {
      TCHAR buffer[512];
      // Restrict the collection to Contacts in our favorite category
      StringCchPrintf(buffer, 512, TEXT("[Categories] = \"%s\""), szCategory);
      hr = this->pItemCol->Restrict((BSTR)buffer, &this->pItemCol);
    }

    ::StringCchCopy(categoryName, CATEGORY_TEXT_LENGTH, szCategory);
    isFavoritesCat = ::_tcsicmp(szCategory, Settings::favorite_category) == 0;
    if (!isFavoritesCat)
      SetHeaderText(categoryName);
  }
  else
  {
    categoryName[0] = 0;
    isFavoritesCat = false;
  }

  return SUCCEEDED(hr);
}

void ListDataPoom::Populate()
{
  if (!this->pItemCol)
    return;

  int cItems = 0;
  bool bOnlyFavorites = this->bOnlyFavorites;

  this->pItemCol->get_Count(&cItems);

  if (cItems == 0 && bOnlyFavorites)
    return;

  bool fillGroup = !bOnlyFavorites || Settings::enableFavoritesSearch;

  // first item in the list is "Add new contact"
  if (!bOnlyFavorites)
  {
    CListItemNewContact* pItem = new CListItemNewContact();
    if (pItem)
    {
      pItem->SetPrimaryText(Language::add_new_contact);
      Add(pItem);
    }
  }

#ifdef LOG_ENABLED
  Logger::LogFmt(TEXT("ListDataPoom::Populate: %d"), cItems);
#endif

  IContact* pContact = NULL;
  for (int i = 1; i <= cItems; i++)
  {
    if (FAILED(this->pItemCol->Item(i, reinterpret_cast<IDispatch**>(&pContact))))
    {
      continue;
    }

    CListItemPoom* pItem = new CListItemPoom();
    if (pItem)
    {
      if (FillContact(pItem, pContact, fillGroup))
        Add(pItem);
      else
        delete pItem;
    }

    pContact->Release();

    ::SendMessage(parentWnd, NM_UPDATE_BUSY_PROGRESS, 0, (LPARAM)((i * 100) / cItems));
  }
}

bool ListDataPoom::FillContact(CListItemPoom* pItem, IContact* pContact, bool fillGroup, bool reload)
{
  if (!pContact || !pItem)
    return false;

  HRESULT hr;

  // Grab Properties
  long oId = 0;
  hr = pContact->get_Oid(&oId);
  pItem->oId = oId;

  BSTR bstr;
  hr = pContact->get_FileAs(&bstr);
  if (SUCCEEDED(hr))
  {
    pItem->SetPrimaryText(bstr);
  }
  SysFreeString(bstr);

  // grab dialing number
  if (Settings::showDialingNumber || Settings::longTapDelay)	// TODO: set dialing number position
  {
    TCHAR tDial[PRIMARY_TEXT_LENGTH] = {0};
    TCHAR tSuffix[PRIMARY_TEXT_LENGTH] = {0};
    SetDialingNumber(pItem->oId, pContact, tDial, tSuffix, PRIMARY_TEXT_LENGTH, pItem->dialingNumberProp);
    pItem->SetDialingNo(tDial, tSuffix);
  }

  if (Settings::highlightFavsInList)
  {
    hr = pContact->get_Categories(&bstr);
    if (SUCCEEDED(hr))
    {
      pItem->isFavorite = (NULL != _tcsstr(bstr, Settings::favorite_category));
    }
    SysFreeString(bstr);
  }

  if (fillGroup)
    pItem->wcGroup = _totupper(pItem->szPrimaryText[0]);

  // add load picture task
  if (Settings::showPicturesInList)
  {
    pItem->picture = PoomPictures::Add(pItem->oId, Theme::ListPictureWidth, Theme::ListPictureHeight, reload);
  }

  return true;
}

void ListDataPoom::PopulateSim()
{
  ClearFilter();

  long numEntries = SimManager::GetActiveContactsCount();
  if (numEntries == 0)
  {
    return;
  }

  CList::CListItems newArray;
  newArray.reserve(this->items.size() + numEntries);

  size_t itemsPos = 0;
  // Copy "Create New Item" (we are never in Favorites when in PopulateSim)
  if (this->items.size() > 0)
  {
    newArray.push_back(this->items[0]);
    itemsPos++;
  }

  long i = 0;
  TCHAR szName[PRIMARY_TEXT_LENGTH];
  TCHAR szNumber[PRIMARY_TEXT_LENGTH];
  while (SimManager::GetNextActiveContact(i, szName, PRIMARY_TEXT_LENGTH, szNumber, PRIMARY_TEXT_LENGTH))
  {
    if (szName[0] == 0)
      continue;

    // copy all items prior to current one
	size_t len = this->items.size();
    for (size_t n = itemsPos; n <= len; ++n)
    {
      if (n == (long)this->items.size() ||
          _tcsicmp(BaseItem(n)->szPrimaryText, szName) > 0)
      {
        if (n > itemsPos)
        {
          for (; itemsPos < n; itemsPos++)
            newArray.push_back(this->items[itemsPos]);
        }
        break;
      }
    }

    CListItemSim* pData = new CListItemSim();
    if (pData)
    {
      pData->SetHeight(defaultItemHeight);
      pData->SetPrimaryText(szName);
      pData->SetDialingNo(szNumber, _T("")); 
      pData->wcGroup = _totupper(pData->szPrimaryText[0]);
      newArray.push_back(pData);
    }
  }

  // copy all remaining items
  size_t N = this->items.size();
  for (; itemsPos < N; itemsPos++)
  {
    newArray.push_back(this->items[itemsPos]);
  }

  this->items.clear();
  this->items = newArray;
}

bool ListDataPoom::SetDialingNumber(CEOID oId, IContact* pContact, TCHAR* tszNumber, TCHAR* tszSuffix, int nMaxLength, CEPROPID& propId)
{
  if (!pContact)
    return false;

  HRESULT hr;

  IItem* pItem = NULL;
  if (Settings::smartDialingNumber)
  {
    hr = pContact->QueryInterface(IID_IItem, (LPVOID*)&pItem);
    if (SUCCEEDED(hr))
    {
      // try to get number from the smart property
      PropertyValues vals;
      if (PoomData::GetItemProperty(pItem, PIMPR_SMARTPROP, vals))
      {
        if ((vals[0].wFlags & CEDB_PROPNOTFOUND) == 0)
        {
          CEPROPID val = vals[0].val.ulVal;

          // Set the suffix
          switch(val)
          {
          case PIMPR_ASSISTANT_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumA);
            break;
          case PIMPR_BUSINESS_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumW);
            break;
          case PIMPR_BUSINESS2_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumW2);
            break;
          case PIMPR_CAR_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumCar);
            break;
          case PIMPR_COMPANY_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumCo);
            break;
          case PIMPR_HOME_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumH);
            break;
          case PIMPR_HOME2_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumH2);
            break;
          case PIMPR_MOBILE_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumM);
            break;
          case PIMPR_PAGER_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumPgr);
            break;
          case PIMPR_RADIO_TELEPHONE_NUMBER:
            StringCchCopy(tszSuffix, nMaxLength, Language::abrNumRdo);
            break;
          }

          // Set the number
          switch(val)
          {
          case PIMPR_ASSISTANT_TELEPHONE_NUMBER:
          case PIMPR_BUSINESS_TELEPHONE_NUMBER:
          case PIMPR_BUSINESS2_TELEPHONE_NUMBER:
          case PIMPR_CAR_TELEPHONE_NUMBER:
          case PIMPR_COMPANY_TELEPHONE_NUMBER:
          case PIMPR_HOME_TELEPHONE_NUMBER:
          case PIMPR_HOME2_TELEPHONE_NUMBER:
          case PIMPR_MOBILE_TELEPHONE_NUMBER:
          case PIMPR_PAGER_NUMBER:
          case PIMPR_RADIO_TELEPHONE_NUMBER:
            if (PoomData::GetItemProperty(pItem, val, vals))
            {
              if (EdbData::GetPropertyValue(vals[0], tszNumber, nMaxLength))
              {
                propId = val;
                vals.Free();
                pItem->Release();
                return true;
              }
            }
            break;
          }
        }
        vals.Free();
      }
    }
  }

  BSTR buffer;
  bool found = false;
  CEPROPID foundProp = 0;
  // Try to get Mobile Number
  hr = pContact->get_MobileTelephoneNumber(&buffer);
  if(SUCCEEDED(hr))
  {
    if (buffer[0] != 0)
    {
      StringCchCopy(tszNumber, nMaxLength, buffer);
      StringCchCopy(tszSuffix, nMaxLength, Language::abrNumM);
      found = true;
      foundProp = PIMPR_MOBILE_TELEPHONE_NUMBER;
    }
  }
  SysFreeString(buffer);

  if (!found)
  {
    // Try to get Home Number
    hr = pContact->get_HomeTelephoneNumber(&buffer);
    if(SUCCEEDED(hr))
    {
      if (buffer[0] != 0)
      {
        StringCchCopy(tszNumber, nMaxLength, buffer);
        StringCchCopy(tszSuffix, nMaxLength, Language::abrNumH);
        found = true;
        foundProp = PIMPR_HOME_TELEPHONE_NUMBER;
      }
    }
    SysFreeString(buffer);
  }

  if (!found)
  {
    // Try to get Business Number
    hr = pContact->get_BusinessTelephoneNumber(&buffer);
    if(SUCCEEDED(hr))
    {
      if (buffer[0] != 0)
      {
        StringCchCopy(tszNumber, nMaxLength, buffer);
        StringCchCopy(tszSuffix, nMaxLength, Language::abrNumW);
        found = true;
        foundProp = PIMPR_BUSINESS_TELEPHONE_NUMBER;
      }
    }
    SysFreeString(buffer);
  }

  if (found && pItem != NULL)
  {
    CEPROPVAL propVal;
    propVal.propid = PIMPR_SMARTPROP;
    propVal.wLenData = 0;
    propVal.wFlags = 0;
    propVal.val.ulVal = foundProp;
    if (PoomData::SetItemProperty(pItem, propVal))
    {
      hr = pItem->Save();
      if (SUCCEEDED(hr))
        propId = foundProp;
    }
  }

  if (pItem)
    pItem->Release();

  return false;
}